package org.oos.atom;

import static org.oos.atom.AtomResponse.ResponseType.Empty;
import static org.oos.atom.AtomResponse.ResponseType.Error;
import static org.oos.atom.AtomResponse.ResponseType.Unknown;
import static org.oos.atom.AtomResponse.ResponseType.Valid;

import com.google.api.client.http.HttpResponse;
import com.google.common.base.Preconditions;

public class AtomResponse<F extends AtomEntity> {

	private final F result;
	private final Throwable throwable;
	private final HttpResponse httpResponse;
	private final ResponseType type;

	public static <Entity extends AtomEntity> Builder<Entity> responseBuilder() {
		return new Builder<Entity>();
	}
	
	public static enum ResponseType {
		Valid, Empty, Error, Unknown;
	}

	protected AtomResponse(F result, Throwable throwable,
			HttpResponse httpResponse) {
		super();
		this.result = result;
		this.throwable = throwable;
		this.httpResponse = httpResponse;
		if (throwable != null) {
			type = Error;
		}else if (result != null) {
			type = Valid;
		} else if (httpResponse!=null && httpResponse.isSuccessStatusCode() && result == null) {
			type = Empty;
		} else {
			type = Unknown;
		}
		
	}
	
	/**
	 * 
	 * @author pablisco
	 * 
	 * Builder for {@link AtomResponse}
	 *
	 * @param <Entity>
	 */
	public static class Builder<Entity extends AtomEntity> {

		private HttpResponse httpResponse;
		private Throwable throwable;

		private Builder() {
		}

		public AtomResponse<Entity> build(Class<Entity> clazz) {
			Entity result = null;
			Throwable exception = throwable;
			try {
				if (httpResponse == null) {
					result = clazz.newInstance();
				} else if (clazz != null) {
					result = httpResponse.parseAs(clazz);
				}
			} catch (Exception e) {
				if(!(httpResponse.getStatusCode()==200 || httpResponse.getStatusCode()==201))
					exception = e;
			}
			return new AtomResponse<Entity>(result, exception, httpResponse);
		}

		public Builder<Entity> setThrowable(Throwable throwable) {
			this.throwable = throwable;
			
			return this;
		}

		/**
		 * @param httpResponse
		 *            the httpResponse to set
		 */
		public Builder<Entity> setHttpResponse(HttpResponse httpResponse) {
			this.httpResponse = httpResponse;
			return this;
		}

	}
	
	/**
	 * @return the result
	 */
	public F getResult() {
		return result;
	}
	
	public ResponseType getType() {
		return type;
	}

	/**
	 * @return the throwable
	 */
	public Throwable getThrowable() {
		return throwable;
	}

	public HttpResponse getHttpResponse() {
		return httpResponse;
	}

}
